package com.yonyou.crm.sact.outwork.service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.yonyou.crm.bpub.detail.entity.LocationVO;
import com.yonyou.crm.common.biz.service.BaseBizServiceImpl;
import com.yonyou.crm.common.exception.CrmBusinessException;
import com.yonyou.crm.common.login.context.LoginContextConstant;
import com.yonyou.crm.sact.outwork.entity.RuleTimeListVO;
import com.yonyou.crm.sact.outwork.entity.TraceListVO;
import com.yonyou.crm.sact.outwork.entity.TraceVO;
import com.yonyou.crm.sys.user.entity.UserVO;
import com.yonyou.crm.sys.user.service.UserBizServiceImpl;
import com.yonyou.iuap.context.InvocationInfoProxy;

@Service
public class TraceBizServiceImpl extends BaseBizServiceImpl<TraceVO> {

	@Autowired
	private UserBizServiceImpl userService;
	
	@Autowired
	private OutworkRuleBizServiceImpl ruleService;
	
	@Override
	protected void beforeSaveVO(TraceVO vo) {
		super.beforeSaveVO(vo);

		String userIdStr = (String)InvocationInfoProxy.getParameter(LoginContextConstant.UserId);//用户id
		String orgIdStr = (String)InvocationInfoProxy.getParameter(LoginContextConstant.OrgId);//所属公司
		String deptIdStr = (String)InvocationInfoProxy.getParameter(LoginContextConstant.DeptId);//所属部门
		Long userId = Long.parseLong(userIdStr);
		Long orgId = Long.parseLong(orgIdStr);
		Long deptId = Long.parseLong(deptIdStr);

		Date date = new Date();

		vo.setUserId(userId);
		vo.setSignTime(date);
		
		vo.setOrgId(orgId);
		vo.setDeptId(deptId);
	}
	
	public List<TraceListVO> getTraceList(Map<String, Object> paraMap) {
		String tenantIdStr = (String)InvocationInfoProxy.getTenantid();
		Long tenantId = Long.parseLong(tenantIdStr);
		paraMap.put("tenantId", tenantId);

		if (!paraMap.containsKey("userId")) {
			String userIdStr = (String)InvocationInfoProxy.getParameter(LoginContextConstant.UserId);//用户id
			Long userId = Long.parseLong(userIdStr);
			paraMap.put("userId", userId);
		}
		
		List<TraceVO> traceVOs = dao.selectVoList(TraceVO.class, "selectTraces", paraMap);
		
		List<TraceListVO> rsList = new ArrayList<TraceListVO>();
		SimpleDateFormat sdf = new SimpleDateFormat("hh:mm");
		for (TraceVO vo : traceVOs) {
			TraceListVO listVO = new TraceListVO();
			listVO.setId(vo.getId());
			listVO.setTime(sdf.format(vo.getSignTime()));
			listVO.setNote(vo.getNote());
			LocationVO location = new LocationVO();
			location.setAddress(vo.getAddress());
			location.setLatitude(vo.getLatitude());
			location.setLongitude(vo.getLongitude());
			listVO.setLocation(location);
			List<String> piclist = new ArrayList<String>();
			if (vo.getNoteFile() != null && !vo.getNoteFile().isEmpty()) {
				String[] picStrings = vo.getNoteFile().split(",");
				for (String picStr : picStrings) {
					if (!picStr.isEmpty()) {
						piclist.add(picStr);
					}
				}
			}
			
			listVO.setPiclist(piclist);
			rsList.add(listVO);
		}
		return rsList;
	}
	
	/*
	 * 根据当前登录用户的角色，获取有权限的用户id数组，传入参数为用户id字符串数组
	 * @return 当传入参数为空时，返回有权限的id数组，不为空时，返回结果为过滤掉无权限id的数据
	 */
	private List<Long> getUserIdsByRole(List<Long> userIdList) {
		String userIdStr = (String)InvocationInfoProxy.getParameter(LoginContextConstant.UserId);//用户id
		Long userId = Long.parseLong(userIdStr);

		UserVO user = userService.getDetail(userId);
		List<Long> userIds = new ArrayList<Long>();
		if (userIdList == null) {
			Integer userJob = user.getJob(); // TODO 将来需要根据登录人角色做判断，这里暂时先使用是否负责人状态
		
			if (userJob > 1) {
				List<Map<String, Object>> deptUserList = userService.getUserByDeptId(null,"");
				for (Map<String, Object> map : deptUserList) {
					userIds.add((Long)map.get("id"));
				}
			} else {
				userIds.add(userId);
			}
		} else {
			userIds.add(userId);
			// TODO 将来需要判断当前登录用户是否对userList中的用户有权限
			for (Long subId : userIdList) {
				if (!userIds.contains(subId)) {
					userIds.add(subId);
				}
			}
		}
		
		return userIds;
	}
	
	/*
	 * 获取打卡列表(返回多用户打卡时间列表，用于计算缺勤状态和打卡次数)
	 * @paraMap userIds:用户id数组(不能为空)，startDate:查询的开始日期(yyyy-MM-dd),endDate:查询的结束日期
	 * @return key:用户id，value:打卡时间数组(未打卡人员返回空数组)
	 */
	@SuppressWarnings("unchecked")
	private Map<String, List<Date>> getUserSignTimeList(Map<String, Object> paraMap) {
		// 查询符合条件的打卡记录
		List<TraceVO> signTimeVos = dao.selectVoList(TraceVO.class, "selectSignTimes", paraMap);
		// 将返回数据封装成Map<id, List<signTime>>的格式返回，缺勤日期列表和下属员工考勤列表由这个方法计算。
		Map<String, List<Date>> rsMap = new HashMap<String,List<Date>>();
		
		for (TraceVO signTimeVo : signTimeVos) {
			String uidStr = signTimeVo.getUserId().toString();
			Date signTime = signTimeVo.getSignTime();
			List<Date> signTimeList = new ArrayList<Date>();
			if (rsMap.containsKey(uidStr)) {
				signTimeList = rsMap.get(uidStr);
			}
			signTimeList.add(signTime);
			rsMap.put(uidStr, signTimeList);
		}
		
		// 补全为打卡人员
		List<Long> userIds = (List<Long>)paraMap.get("userIds");
		for (Long uid : userIds) {
			String uidStr = uid.toString();
			if (!rsMap.containsKey(uidStr)) {
				List<Date> signTimeList = new ArrayList<Date>();
				rsMap.put(uidStr, signTimeList);
			}
		}
		return rsMap;
	}
	
	
	@SuppressWarnings("unchecked")
	private List<Map<String, Object>> getSignTimeList(Boolean isOpenRule, List<RuleTimeListVO> ruleList, Map<String, Object> paraMap) {
		String tenantIdStr = (String)InvocationInfoProxy.getTenantid();
		Long tenantId = Long.parseLong(tenantIdStr);
		
		Map<String, Object> filterMap = new HashMap<String, Object>();
		paraMap.put("tenantId", tenantId);
		filterMap.put("tenantId", tenantId);
		
		// mysql查询时，起止日期要精确到秒
		if (paraMap.containsKey("startDate")) {
			filterMap.put("startTime", paraMap.get("startDate") + " 00:00:00");
		}
		if (paraMap.containsKey("endDate")) {
			filterMap.put("endTime", paraMap.get("endDate") + " 23:59:59");
		}
		
		List<Long> userIds = new ArrayList<Long>();
		if (paraMap.get("userList") != null) {
			List<String> userIdList = (List<String>)paraMap.get("userList");
			for (String uidStr : userIdList) {
				if (uidStr != null && !uidStr.isEmpty()) {
					userIds.add(Long.parseLong(uidStr));
				}
			}
		}
		userIds = getUserIdsByRole(userIds);
		if (userIds.isEmpty()) {
			throw new CrmBusinessException("获取用户id错误");
		}
		
		filterMap.put("userIds", userIds);
		Map<String, List<Date>> map = getUserSignTimeList(filterMap);
		
		// 返回数组，数组元素为Map<String, Object>,key包含userId, signTimeList(出勤时间数组), absenceTimeRangeMap(缺勤时间段数组)
		List<Map<String, Object>> rsList = new ArrayList<Map<String,Object>>();
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm");

		int ruleNum = ruleList.size();
		for (Long uid : userIds) {
			Map<String, Object> signMap = new HashMap<String, Object>();
			List<Date> signTimeList = new ArrayList<Date>();
			
			signMap.put("userId", uid);
			String uidStr = uid.toString();
			if (map.containsKey(uidStr)) {
				signTimeList = map.get(uidStr);
			}
			signMap.put("signTimeList", signTimeList);

			// 出勤时间用Map<String, List<String>>表示，key为出勤日期，value为打卡时间(HH-mm)
			Map<String, List<String>> signDateMap = new HashMap<String, List<String>>();
			if (signTimeList.size() > 0) {
				for (Date time : signTimeList) {
					String signDateStr = "";
					String signTimeStr = "";
					signDateStr = dateFormat.format(time);
					signTimeStr = timeFormat.format(time);
					
					List<String> timeList = new ArrayList<String>();
					if (signDateMap.containsKey(signDateStr)) {
						timeList = signDateMap.get(signDateStr);
					}
					timeList.add(signTimeStr);
					signDateMap.put(signDateStr, timeList);
				}
			}
			
			// 缺勤时间段Map<String, List<String>>，key为日期(yyyy-MM-dd)，value为时间段(HH:mm-HH:mm)
			Map<String, List<String>> absenceTimeRangeMap = new HashMap<String, List<String>>();
			if (isOpenRule) {
				for (String signDateStr : signDateMap.keySet()) {
					List<String> timeList = signDateMap.get(signDateStr);
					int[] nomalSignNum = new int[ruleNum];
					for (String time : timeList) {
						int i = 0;
						for (RuleTimeListVO ruleTimeVo : ruleList) {
							if (time.compareTo(ruleTimeVo.getStarttime()) >= 0 && time.compareTo(ruleTimeVo.getEndtime()) <= 0) {
								nomalSignNum[i] = 1;
								break;
							}
							i++;
						}
					}
					
					List<String> absenceTimeList = new ArrayList<String>();
					for (int i=0; i<ruleNum; i++) {
						if (nomalSignNum[i] == 0) {
							absenceTimeList.add(ruleList.get(i).getStarttime() + "-" +ruleList.get(i).getEndtime());
						}
					}
					absenceTimeRangeMap.put(signDateStr, absenceTimeList);
					
				}
				
			}
			signMap.put("absenceTimeRangeMap", absenceTimeRangeMap);
			rsList.add(signMap);
		}
		
		return rsList;
	}
	
	/*
	 * 取缺勤日期列表
	 */
	@SuppressWarnings("unchecked")
	public List<String> getAbsenceDateList(Map<String, Object> paraMap) {
		List<String> rsList = new ArrayList<String>();
		
		// 取考勤规则，如果没有设置规则，返回空数组
		Map<String, Object> ruleMap = ruleService.getRule(paraMap);
		boolean isOpenRule = (boolean)ruleMap.get("isOpenRule");
		List<RuleTimeListVO> ruleList = (List<RuleTimeListVO>)ruleMap.get("ruleList");
		if (!isOpenRule) {
			return rsList;
		}
		
		String startDateStr = (String)paraMap.get("startDate");
		String endDateStr = (String)paraMap.get("endDate");

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		
		try {
			Date startDate = sdf.parse(startDateStr);
			Date endDate = sdf.parse(endDateStr);
			
			// 根据考勤规则设定时间设定起止时间，截至时间为当天，开始时间为考勤规则生效时间
			if (ruleMap.containsKey("startDate")) {
				Date ruleStartDate = (Date)ruleMap.get("startDate");
				if (ruleStartDate.after(startDate)) {
					startDate = ruleStartDate;
				}
			}
	    	Date todayDate = new Date();
	    	if (endDate.after(todayDate)) {
	    		endDate = todayDate;
	    	}
			
			List<Date> listDate = getDatesBetweenTwoDate(startDate, endDate);
		
			List<Map<String, Object>> signTimeList = getSignTimeList(isOpenRule, ruleList, paraMap);
			List<String> notAbsenceDateList = new ArrayList<String>();
			for (Map<String, Object> signTimeListMap : signTimeList) {
				@SuppressWarnings("rawtypes")
				Map<String, List> aMap = (Map<String, List>)signTimeListMap.get("absenceTimeRangeMap");
				Set<String> keys = aMap.keySet();
				for(String key :keys) {
					if (aMap.get(key).size() == 0) {
						notAbsenceDateList.add(key);
					}
				}
			}
			
		    for(int i = 0; i < listDate.size(); i++){
		         Date date = listDate.get(i);
		         String dateStr = sdf.format(date);
		         if (!notAbsenceDateList.contains(dateStr)) {
		        	 rsList.add(dateStr);
		         }
		         
		    }
		} catch (ParseException e) {
			throw new CrmBusinessException("时间格式转化错误");
		}
		return rsList;
	}
	
	/** 
     * 根据开始时间和结束时间返回时间段内的时间集合 
     *  
     * @param beginDate 
     * @param endDate 
     * @return List 
     */  
    private static List<Date> getDatesBetweenTwoDate(Date startDate, Date endDate) {
        List<Date> lDate = new ArrayList<Date>();
        lDate.add(startDate);// 把开始时间加入集合  
        Calendar cal = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间  
        cal.setTime(startDate);
        boolean bContinue = true;  
        while (bContinue) {  
            // 根据日历的规则，为给定的日历字段添加或减去指定的时间量  
            cal.add(Calendar.DAY_OF_MONTH, 1);  
            // 测试此日期是否在指定日期之后  
            if (endDate.after(cal.getTime())) {  
                lDate.add(cal.getTime());  
            } else {  
                break;  
            }  
        }  
        lDate.add(endDate);// 把结束时间加入集合  
        return lDate;  
    }
	
	@SuppressWarnings("unchecked")
	public Map<String, Object> getSubworks(Map<String, Object> paraMap) {
		// 取考勤规则，如果没有设置规则，返回空数组
		Map<String, Object> ruleMap = ruleService.getRule(paraMap);
		boolean isOpenRule = (boolean)ruleMap.get("isOpenRule");
		List<RuleTimeListVO> ruleList = (List<RuleTimeListVO>)ruleMap.get("ruleList");
				
		List<Map<String, Object>> list = getSignTimeList(isOpenRule, ruleList, paraMap);
		
		String userIdStr = (String)InvocationInfoProxy.getParameter("id");//用户id
		Long userId = Long.parseLong(userIdStr);
		
		List<Map<String, Object>> deptUserList = userService.getUserByDeptId(null,"");
		Map<String, String> userNameMaps = new HashMap<String, String>();
		for (Map<String, Object> userMap : deptUserList) {
			userNameMaps.put(String.valueOf(userMap.get("id")), (String)userMap.get("name"));
		}

		List<Map<String, String>> myoutworkslist = new ArrayList<Map<String, String>>();
		List<Map<String, String>> suboutworkslist = new ArrayList<Map<String, String>>();
		
		for (Map<String, Object> map : list) {
			Long uId = (Long)map.get("userId");
			Map<String, String> outworkMap = new HashMap<String, String>();
			outworkMap.put("id", uId.toString());
			outworkMap.put("name", userNameMaps.get(uId.toString()));
			String dateStr = (String)paraMap.get("startDate");
			Map<String, List<String>> absenceTimeRangeMap = (Map<String, List<String>>)map.get("absenceTimeRangeMap");
			List<String> absenceTimeRange = absenceTimeRangeMap.get(dateStr);
			String isAbsence = "N";
			if (absenceTimeRange != null && !absenceTimeRange.isEmpty()) {
				isAbsence = "Y";
			}
			outworkMap.put("isabsence", isAbsence);
			List<Date> signTimeList = new ArrayList<Date>();
			if (map.get("signTimeList") != null) {
				signTimeList = (List<Date>)map.get("signTimeList");
			}
			
			outworkMap.put("num", String.valueOf(signTimeList.size()));
			if (userId.equals(uId)) {
				myoutworkslist.add(outworkMap);
			} else {
				suboutworkslist.add(outworkMap);
			}
		}
		
		Map<String, Object> rsMap = new HashMap<String, Object>();
		rsMap.put("myoutworkslist", myoutworkslist);
		rsMap.put("suboutworkslist", suboutworkslist);
		
		return rsMap;
	}
	
}
